import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;


public class MySqlUtil implements SqlUtil {
    /**
     * query方法一定程度上参考了CSDN文章
     * https://blog.csdn.net/molu_chase/java/article/details/52225581*/
    @Override
    public String query(User user) {
        Class clazz = user.getClass();
        StringBuffer sqlQuery = new StringBuffer();
        //如果传入的参数不包含Table注释，则返回null
        if(!clazz.isAnnotationPresent(Table.class)) {
            //System.out.println("error1");
            return null;}
        //获取Table类注解
        Table table = (Table)clazz.getAnnotation(Table.class);

        String tableName = table.value();

        sqlQuery.append("SELECT * FROM `"+tableName+"` WHERE ");

        sqlQuery.append(getJudgement(user));

        return sqlQuery.toString();
    }

    @Override
    public String insert(User user) {
        Class clazz = user.getClass();
        StringBuffer sqlInsert = new StringBuffer();
        //如果传入的参数不包含Table注释，则返回null
        if(!clazz.isAnnotationPresent(Table.class)) {
            return null;}
        //获取Table类注解
        Table table = (Table)clazz.getAnnotation(Table.class);
        String tableName = table.value();
        sqlInsert.append("INSERT INTO `"+tableName+"` ");
        //用list来存放属性值，便于后续调用
        List<Object> fieldValues = getFieldValues(user);
        //在Insert语句中添加 属性名的元组
        sqlInsert.append(getColumnTuple(user));

        sqlInsert.append(" VALUES ");

        //待所有fieldName都放进sql语句后，开始按顺序放值的元组

        sqlInsert.append(getValueTuple(fieldValues));

        return sqlInsert.toString();
    }

    @Override
    public String insert(List<User> users) {
        StringBuffer sqlInsert = new StringBuffer();
        boolean isFirstUser = true;
        for(User user: users){
            if(user == null){continue;}
            //对于第一个user，直接调用Insert(User user)方法，之后只需要继续添加属性值元组
            if(isFirstUser){
                sqlInsert.append(insert(user));
            }
            //对于第二个及以后的user，直接获取属性值生成tuple附加在语句后面
            else {
                sqlInsert.append(",");
                sqlInsert.append(getValueTuple(getFieldValues(user)));
            }
            isFirstUser = false;
        }
        return sqlInsert.toString();
    }

    @Override
    public String delete(User user) {
        StringBuffer sqlDelete = new StringBuffer();
        sqlDelete.append("DELETE FROM ");
        Class clazz = user.getClass();
        //如果传入的参数不包含Table注释，则返回null
        if(!clazz.isAnnotationPresent(Table.class)) {
            //System.out.println("error1");
            return null;}
        //获取Table类注解
        Table table = (Table)clazz.getAnnotation(Table.class);
        sqlDelete.append("`").append(table.value()).append("` WHERE ");

        sqlDelete.append(getJudgement(user));

        return sqlDelete.toString();
    }

    @Override
    public String update(User user) {
        StringBuffer sqlUpdate = new StringBuffer();
        Class clazz = user.getClass();
        //如果传入的参数不包含Table注释，则返回null
        if(!clazz.isAnnotationPresent(Table.class)) {
            return null;}
        //获取Table类注解
        Table table = (Table)clazz.getAnnotation(Table.class);
        sqlUpdate.append("UPDATE `").append(table.value()).append("` SET ");
        String judgement = getJudgement(user);

        //从judgement字符串中分离出“id=xxx”和其他判断子串
        int spaceIndex = judgement.indexOf(" ",7);
        String idJudgement = judgement.substring(0,spaceIndex);
        String otherJudgement = judgement.substring(spaceIndex+5);//去掉多余的 “ AND ”

        sqlUpdate.append(otherJudgement).append(" WHERE ").append(idJudgement);

        return sqlUpdate.toString();
    }

    /**获得属性名的元组*/
    private String getColumnTuple(User user){
        Class c = user.getClass();
        StringBuffer columnTuple = new StringBuffer();
        columnTuple.append("(");

        Field[] fields = c.getDeclaredFields();
        boolean isFirstField = true;
        for(Field field : fields){
            //通过注释中的值获取属性名
            String columnValue = field.getAnnotation(Column.class).value();
            Object fieldValue = getFieldValue(columnValue,user);
            //未提供属性值时直接跳过这个属性名
            if (fieldValue == null || ((fieldValue instanceof Integer) && ((Integer) fieldValue == 0))) {
                continue;
            }
            //当该field不是第一个的时候需要加上 ,
            if(!isFirstField){ columnTuple.append(","); }
            columnTuple.append("`").append(columnValue).append("`");
            //在第一次append之后每一次都要先加 ,
            isFirstField = false;
        }
        columnTuple.append(")");
        return columnTuple.toString();
    }
    /**获得属性值的元组*/
    private String getValueTuple(List<Object> fVs){
        boolean isFirstValue = true;
        StringBuffer valueTuple = new StringBuffer();
        valueTuple.append("(");
        for(Object o: fVs){
            if(!isFirstValue){valueTuple.append(",");}
            valueTuple.append("`").append(o.toString()).append("`");
            isFirstValue = false;
        }
        valueTuple.append(")");
        return valueTuple.toString();
    }
    /**得到所有属性值的List*/
    private List<Object> getFieldValues(User user){
        List<Object> fieldValues = new ArrayList<>();
        Class c = user.getClass();
        Field[] fields = c.getDeclaredFields();
        for(Field field: fields){
            //通过注释中的值获取属性名
            String columnValue = field.getAnnotation(Column.class).value();

            Object fieldValue = getFieldValue(columnValue,user);

            //属性未赋值则不需要插入
            if (fieldValue == null || ((fieldValue instanceof Integer) && ((Integer) fieldValue == 0))) {
                continue;
            }
            fieldValues.add(fieldValue);
        }
        return fieldValues;
    }
    /**通过属性名invoke get方法 获取属性值*/
    private Object getFieldValue(String columnV, User user){
        //获取属性的getter方法名
        String getMethodName = "get" + columnV.substring(0, 1).toUpperCase() + columnV.substring(1);
        //使用反射invoke属性的getter方法，获取属性值 由于类型未知，使用Object类来承接
        Object fieldValue = null;
        try {
            Method getMethod = (user.getClass()).getMethod(getMethodName);
            fieldValue = getMethod.invoke(user);
        } catch (NoSuchMethodException | IllegalAccessException | SecurityException | IllegalAccessError | InvocationTargetException e) {
        }
        return fieldValue;
    }
    /**获取SELECT和DELETE语句中的条件判断语句*/
    private String getJudgement(User user){
        StringBuffer jugdement = new StringBuffer();
        Class clazz = user.getClass();
        //获取声明的属性
        Field[] fields = clazz.getDeclaredFields();
        boolean isFirstField = true;
        for(Field field: fields){

            //通过注释中的值获取属性名
            String columnValue = field.getAnnotation(Column.class).value();

            Object fieldValue = getFieldValue(columnValue,user);

            //属性未赋值则不需要查找
            if(fieldValue == null||((fieldValue instanceof Integer)&&((Integer)fieldValue==0))){
                continue;
            }
            if(!isFirstField){
                jugdement.append(" AND ");
            }
            jugdement.append("`").append(columnValue).append("`");
            //字符串和数字用不同表示
            if(fieldValue instanceof String){
                jugdement.append(" LIKE ").append("'").append(fieldValue).append("'");
            }else if (fieldValue instanceof Integer) {
                jugdement.append(" = ").append(fieldValue);
            }
            isFirstField = false;
        }
        return jugdement.toString();
    }

}
